module sidearm.opcode;

import std.stdint;
import common;

immutable MNEMONIC_LEN_MAX = 8;

enum AddrMode { Base, Stack, Immediate, Direct, Indirect, Relative, Register, Index }
enum MaskType { Opcode, Operand1, Operand2, Operand3 }
enum OperandType { 
	Empty = 0x0000,
	Register,
	Bit,	// 0 <= bit <= 7
	Address,	// @addr, labels
	Numeric,	// 1, 3+2, 32.04
	String,	// "string"
	Array,			// array[]
	Variable,		// an identifier with an addr
	Logical
}

enum OperandWidth {
	bd = 0x00,
	b8 = 0x01, 
	b8s = 0x02,	// signed version
	b16 = 0x04,
	b16s = 0x08,
	b24 = 0x10,
	b24s = 0x20,
	b32 = 0x40,
	b32s = 0x80
}

enum RegisterType {
	Reg_8, Reg_8s,
	Reg_16, Reg_16s,
	Reg_24, Reg_24s,
	Reg_32, Reg_32s,
	Reg_d
}

class __operand_base
{
public:
	this(OperandType t, OperandWidth w, AddrMode a, ubyte m)
	{
		_otype = t;
		_width = w;
		_mode = a;
		mb = m;
	}

	union {		// value
		ubyte vub;
		byte vb;

		uint16_t vus;
		int16_t vs;
		uint24_t vua;
		int32_t vi;
		uint32_t vui;
		double vd;
		bool vbo;
	}
	union {		// mask
		ubyte mb;
		uint16_t ms;
		uint24_t ma;
		uint32_t mi;
	}
 
	OperandType _otype;
	OperandWidth _width;
	AddrMode	_mode;

	void opAssign(ubyte ub) { 
		this.vub = ub; _otype = OperandType.NumberLiteral; 
		_width = OperandWidth.b8;
	}
	void opAssign(byte b) {
		this.vb = b; _otype = OperandType.NumberLiteral;
		_width = OperandWidth.b8s;
	}
	void opAssign(uint16_t us) {
		this.vus = us; _otype = OperandType.NumberLiteral;
		_width = OperandWidth.b16;
	}
	void opAssign(int16_t s) {
		this.vs = s; _otype = OperandType.NumberLiteral;
		_width = OperandWidth.b16s;
	}
	void opAssign(bool b) {
		this.vbo = b; _otype = OperandType.Logical;
		_width = OperandWidth.b8;
	}
}

class __vmvar : __operand_base
{
public:

private:

}

class __vmreg : __operand_base
{
public:
	this(RegisterType t, char [3] n, ubyte m, ubyte o, bool zero=true)
	{
		OperandWidth w;
		final switch(t)
		{
			case RegisterType.Reg_16:
				w = OperandWidth.b16;
				break;
			case RegisterType.Reg_16s:
				w = OperandWidth.b16s;
				break;
			case RegisterType.Reg_24:
				w = OperandWidth.b24;
				break;
			case RegisterType.Reg_24s:
				w = OperandWidth.b24s;
				break;
			case RegisterType.Reg_32:
				w = OperandWidth.b32;
				break;
			case RegisterType.Reg_32s:
				w = OperandWidth.b32s;
				break;
			case RegisterType.Reg_8:
				w = OperandWidth.b8;
				this.mb = 0xff;
				break;
			case RegisterType.Reg_8s:
				w = OperandWidth.b8s;
				break;
			case RegisterType.Reg_d:
				w = OperandWidth.bd;
				break;
		}	
		super(OperandType.Register,w,AddrMode.Register,m);
		type = t;
		if (zero) { vd = 0.0; }
		offset = o;
		name[0] = n[0]; name[1] = n[1]; name[2] = n[2];
		this.mb = 0x0fU;
	}

private:
	RegisterType type;
	char name[3];
	ubyte offset;	// offset from GPIO Register Base
}

auto _registerMap =
[
	"r0" : __vmreg(RegisterType.Reg_8,"r0", 0xf, 0x00),
	 "r1": __vmreg(RegisterType.Reg_8,"r1",0xf, 0x01),
	 "r2": __vmreg(RegisterType.Reg_8,"r2",0xf,0x02),
	 "r3": __vmreg(RegisterType.Reg_8,"r3",0xf,0x03),
	 "r4": __vmreg(RegisterType.Reg_8,"r4",0xf,0x04),
	 "r5": __vmreg(RegisterType.Reg_8,"r5",0xf,0x05),
	 "r6": __vmreg(RegisterType.Reg_8,"r6",0xf,0x06),
	 "r7": __vmreg(RegisterType.Reg_8,"r7",0xf,0x07),
	 "r8": __vmreg(RegisterType.Reg_8,"r8",0xf,0x08),
	 "r9": __vmreg(RegisterType.Reg_8,"r9",0xf,0x09),
	 "r10": __vmreg(RegisterType.Reg_8s,"r10",0xf,0x0A),
	 "r11": __vmreg(RegisterType.Reg_8s,"r11",0xf,0x0B),
	 "r12": __vmreg(RegisterType.Reg_8s,"r12",0xf,0x0C),
	 "r13": __vmreg(RegisterType.Reg_8s,"r13",0xf,0x0D),
	 "r14": __vmreg(RegisterType.Reg_8s,"r14",0xf,0x0E),
	 "r15": __vmreg(RegisterType.Reg_8s,"r15",0xf,0x0F),
	// xmega GPIO registers stop here
	// atmega|tiny devices below
	 "r16": __vmreg(RegisterType.Reg_8,"r16",0x1f,0x10),
	 "r17": __vmreg(RegisterType.Reg_8,"r17",0x1f,0x11),
	 "r18": __vmreg(RegisterType.Reg_8,"r18",0x1f,0x12),
	 "r19": __vmreg(RegisterType.Reg_8,"r19",0x1f,0x13),
	 "r20": __vmreg(RegisterType.Reg_8,"r20",0x1f,0x14),
	 "r21": __vmreg(RegisterType.Reg_8,"r21",0x1f,0x15),
	 "r22": __vmreg(RegisterType.Reg_8,"r22",0x1f,0x16),
	 "r23": __vmreg(RegisterType.Reg_8,"r23",0x1f,0x17),
	 "r24": __vmreg(RegisterType.Reg_8,"r24",0x1f,0x18),
	 "r25": __vmreg(RegisterType.Reg_8,"r25",0x1f,0x19),
	// xmega .defs these to XH:XL, YH:YL, ZH:ZL
	 "r26": __vmreg(RegisterType.Reg_8,"r26",0x1f,0x1A),
	 "r27": __vmreg(RegisterType.Reg_8,"r27",0x1f,0x1B),
	 "r28": __vmreg(RegisterType.Reg_8,"r28",0x1f,0x1C),
	 "r29": __vmreg(RegisterType.Reg_8,"r29",0x1f,0x1D),
	 "r30": __vmreg(RegisterType.Reg_8,"r30",0x1f,0x1E),
	 "r31": __vmreg(RegisterType.Reg_8,"r31",0x1f,0x1F),
	// sidearm-specific extended registers
	"AA" : __vmreg(RegisterType.Reg_16,"AA", 0x3f, 0x20),
	"AB" : __vmreg(RegisterType.Reg_16,"AB", 0x3f, 0x21),
	"AC" : __vmreg(RegisterType.Reg_16,"AC", 0x3f, 0x22),
	"AD" : __vmreg(RegisterType.Reg_16,"AD", 0x3f, 0x23),
	"AE" : __vmreg(RegisterType.Reg_16,"AE", 0x3f, 0x24),
	"AF" : __vmreg(RegisterType.Reg_16,"AF", 0x3f, 0x25),
	"BA" : __vmreg(RegisterType.Reg_16,"BA", 0x3f, 0x26),
	"BB" : __vmreg(RegisterType.Reg_16,"BB", 0x3f, 0x27),

	"BC" : __vmreg(RegisterType.Reg_16s,"BC", 0x3f, 0x28),
	"BD" : __vmreg(RegisterType.Reg_16s,"BD", 0x3f, 0x29),
	"BE" : __vmreg(RegisterType.Reg_16s,"BE", 0x3f, 0x2A),
	"BF" : __vmreg(RegisterType.Reg_16s,"BF", 0x3f, 0x2B),

	"CA" : __vmreg(RegisterType.Reg_24,"CA", 0x3f, 0x2C),
	"CB" : __vmreg(RegisterType.Reg_24,"CB", 0x3f, 0x2D),
	"CC" : __vmreg(RegisterType.Reg_24,"CC", 0x3f, 0x2E),
	"CD" : __vmreg(RegisterType.Reg_24,"CD", 0x3f, 0x2F),

	"CE" : __vmreg(RegisterType.Reg_24s,"CE", 0x3f, 0x30),
	"CF" : __vmreg(RegisterType.Reg_24s,"CF", 0x3f, 0x31),

	"XA" : __vmreg(RegisterType.Reg_32,"XA", 0x3f, 0x32),
	"XB" : __vmreg(RegisterType.Reg_32,"XB", 0x3f, 0x33),
	"XC" : __vmreg(RegisterType.Reg_32,"XC", 0x3f, 0x34),
	"XD" : __vmreg(RegisterType.Reg_32,"XD", 0x3f, 0x35),

	"YA" : __vmreg(RegisterType.Reg_32,"YA", 0x3f, 0x36),
	"YB" : __vmreg(RegisterType.Reg_32s,"YB", 0x3f, 0x37),
	"YC" : __vmreg(RegisterType.Reg_32s,"YC", 0x3f, 0x38),
	"YD" : __vmreg(RegisterType.Reg_32s,"YD", 0x3f, 0x39),

	"ZA" : __vmreg(RegisterType.Reg_64,"ZA", 0x3f, 0x3A),
	"ZB" : __vmreg(RegisterType.Reg_64,"ZB", 0x3f, 0x3B),
	"ZC" : __vmreg(RegisterType.Reg_64,"ZC", 0x3f, 0x3C),
	"ZD" : __vmreg(RegisterType.Reg_64,"ZD", 0x3f, 0x3D),


];

/*** Deprecated: replaced with above
__vmreg registers[] =
{
	{ 0x00, "r0", 0xf },
	{0x00, "r1", 0xf },
	{ 0x00, "r2", 0xf },
	{ 0x00, "r3", 0xf },
	{ 0x00, "r4", 0xf },
	{ 0x00, "r5", 0xf },
	{ 0x00, "r6", 0xf },
	{ 0x00, "r7", 0xf },
	{ 0x00, "r8", 0xf },
	{ 0x00, "r9", 0xf },
	{ 0x00, "r10", 0xf },
	{ 0x00, "r11", 0xf },
	{ 0x00, "r12", 0xf },
	{ 0x00, "r13", 0xf },
	{ 0x00, "r14", 0xf },
	{ 0x00, "r15", 0xf },	// xmega GPIO registers stop here
	{ 0x00, "r16", 0x1f }, // here down only on non-xmega devices
	{ 0x00, "r17", 0x1f },
	{ 0x00, "r18", 0x1f },
	{ 0x00, "r19", 0x1f },
	{ 0x00, "r20", 0x1f },
	{ 0x00, "r21", 0x1f },
	{ 0x00, "r22", 0x1f },
	{ 0x00, "r23", 0x1f },
	{ 0x00, "r24", 0x1f },
	{ 0x00, "r25", 0x1f },
	{ 0x00, "r26", 0x1f }, // xmega .defs these to XH:XL
	{ 0x00, "r27", 0x1f },
	{ 0x00, "r28", 0x1f }, // YH:YL
	{ 0x00, "r29", 0x1f },
	{ 0x00, "r30", 0x1f }, // ZH:ZL
	{ 0x00, "r31", 0x1f },
		
};
*/

struct __opcode
{
	AddrMode	mode;
	char		mnemonic[MNEMONIC_LEN_MAX+1];
	byte		numOperands;
	int	[3]		masks;
	byte		length;
	OperandType	[3] type;
}

__opcode opcodes[] =
{
	{ AddrMode.Register, "add", 2, {0x00,0x00,0x00},3,{(OperandType.Reg_8b|OperandType.Reg_16b|OperandType.Reg_24b|OperandType.Reg_32b|OperandType.Reg_d), (OperandType.Reg_8b|OperandType.Reg_16b|OperandType.Reg_24b|OperandType.Reg_32b|OperandType.Reg_d), OperandType.Empty }}

};